import axios from "axios";
const fs = require('fs');

let host = 'http://192.168.68.196:5244'
let taskType = 'copy'
let lastDirFile = {
  dir: '',
  name: '',
  find: 0,
  token: '',
  tokenTime: 0,
  Password: '',
  todir: '',
  host: '',
  src: '',
  dst: '',
  taskCount: 5
}
let jsonPath = `${__filename}.json`

async function loadFiles(path: string) {
  let pageNum = 1
  let data: any = {
    page: pageNum,
    password: "",
    path: path,
    per_page: 30,
    refresh: true,
  };
  let bigRsp: any = null
  let count = 0
  let total = 1
  while (count < total) {
    let rsp = await makePost(data, `${host}/api/fs/list`)
    if (rsp.data.code !== 200 || !rsp.data?.data?.content) {
      return bigRsp || rsp
    }
    data.refresh = false
    data.page = ++pageNum
    total = rsp.data.data.total
    count += rsp.data.data.content.length
    if (!bigRsp) {
      bigRsp = rsp
    } else {
      bigRsp.data.data.content = bigRsp.data.data.content.concat(rsp.data.data.content)
    }
  }
  return bigRsp
}

async function sleep(delay:number) {
  return new Promise<void>((resolve, reject) => {
    setTimeout(resolve, delay);
  })
}

function getConfig() {
  let config: any = {
    headers: {
      Authorization: lastDirFile?.token || ''
    }
  }
  return config
}

async function makePost(data: object, url: string) {
  for (let i=0;i<3;++i) {
    let rsp = await axios.post(url, data, getConfig()).catch(err => {
      console.log(url, data, err.code)
    })
    if (rsp?.data?.code !== 200) {
      await sleep(50)
      continue
    }
    return rsp
  }
}

async function mkdir(path: string) {
  let data = { path: path }
  return makePost(data, `${host}/api/fs/mkdir`)
}

async function getToken() {
  let dt = new Date()
  if (lastDirFile && lastDirFile.token && (dt.getTime() - lastDirFile.tokenTime < 24 * 3600 * 1000)) {
    return
  }
  const data = { Username: 'admin', Password: lastDirFile.Password }
  let rsp = await makePost(data, `${host}/api/auth/login`)
  lastDirFile.token = rsp.data.data?.token || ''
  if (lastDirFile.token) {
    lastDirFile.tokenTime = dt.getTime()
  }
}

async function compare(pathDst: string, pathSrc: string, fileList: any) {
  let count = lastDirFile.taskCount
  if (fileList.length >= count) return
  if (fileList.length > 0 && fileList[0].totalSize > 50 * 1024 * 1024 * 1024) {
    return
  }
  let rspSrc = await loadFiles(pathSrc)
  let rspDst = await loadFiles(pathDst)
  if (rspSrc.data.code != rspDst.data.code || rspDst.data.code !== 200 || !rspSrc.data.data || !rspDst.data.data) {
    console.log(`compare load data error.`, rspSrc.data, rspDst.data)
    return
  }
  rspSrc.data.data.content = rspSrc.data.data?.content ? rspSrc.data.data.content : []
  rspDst.data.data.content = rspDst.data.data?.content ? rspDst.data.data.content : []
  if (rspSrc.data.data.content.length != rspDst.data.data.content.length) {
    console.log(`${rspSrc.data.data.content.length}:${pathSrc}, \n${rspDst.data.data.content.length}:${pathDst}`)
  }
  let names = <any>[]
  let objs = {}
  for (let obj of rspDst.data.data.content) {
    if (obj.name.match(/(\.\w+)(\(\d+\))?\1$/)) {
      names.push(obj.name)
    } else {
      objs[obj.name] = obj
    }
  }
  if (names.length > 0) {
    let rsp = await rmFilesInDir(pathDst, names)
    console.log('rm file', names, rsp.data)
  }
  if (lastDirFile.find === 0 && lastDirFile.dir === pathSrc) {
    console.log('dst files:', lastDirFile.name, rspDst.data.data.content.map(obj => obj.name))
    let lst = rspSrc.data.data.content.filter(item => item.name === lastDirFile.name)
    lastDirFile.find = lst.length > 0 ? 0 : 1
  }
  let content = rspSrc.data.data.content.sort( (a,b) => { return a.name.localeCompare(b.name) })
  for (let srcObj of content) {
    if (lastDirFile.find === 0 && lastDirFile.dir) {
      if (lastDirFile.dir === pathSrc && lastDirFile.name === srcObj.name) {
        lastDirFile.find = 1
        continue
      }
    }
    if (objs[srcObj.name] == undefined || objs[srcObj.name].size != srcObj.size) {
      if (srcObj.is_dir) {
        await mkdir(pathDst + '/' + srcObj.name)
      } else {
        srcObj.pathDst = pathDst
        srcObj.pathSrc = pathSrc
        if (fileList.length == 0) {
          srcObj.totalSize = srcObj.size
        } else {
          fileList[0].totalSize = fileList[0].totalSize + srcObj.size
        }
        if (lastDirFile.find === 1 || !lastDirFile.dir) {
          lastDirFile.dir = pathSrc
          lastDirFile.todir = pathDst
          lastDirFile.name = srcObj.name
          fileList.push(srcObj)
          lastDirFile.find = 1
        }
        if (fileList.length >= count) return
        if (fileList.length > 0 && fileList[0].totalSize > 50 * 1024 * 1024 * 1024) {
          return
        }
      }
    }
  }
  for (let srcObj of rspSrc.data.data.content) {
    if (srcObj.is_dir) {
      await compare(pathDst + '/' + srcObj.name, pathSrc + '/' + srcObj.name, fileList)
      if (fileList.length >= count) break
    }
  }
}

async function addTask(fileList: any) {
  if (!fileList) return
  let lst = []
  let path2lst = {}
  for (let obj of fileList) {
    if (path2lst[obj.pathDst] == undefined) {
      path2lst[obj.pathDst] = []
    }
    let path = `${host}/d${obj.pathSrc}/${obj.name}?sign=${obj.sign}`
    path2lst[obj.pathDst].push(path)
  }
  let url = `${host}/api/fs/add_aria2`
  for (let path of Object.keys(path2lst)) {
    console.log(path, path2lst[path][0])
    let data = {
      path: path,
      urls: path2lst[path]
    }
    let rsp = await makePost(data, url)
    console.log('add_aria2', rsp.data)
    // lst.push(makePost(data, url))
  }
  return Promise.all(lst)
}

async function copyTask(fileList: any) {
  if (!fileList) return
  let dir2names = {}
  let url = `${host}/api/fs/copy`
  let req = { dst_dir: '', src_dir: '', names: <any>[] }
  let reqs = {}
  for (let obj of fileList) {
    req = reqs[obj.pathSrc] || { dst_dir: '', src_dir: '', names: <any>[] }
    req.dst_dir = obj.pathDst
    req.src_dir = obj.pathSrc
    req.names.push(obj.name)
    reqs[obj.pathSrc] = req
  }
  let lst = Object.values(reqs) as Array<Object>
  for (let req of lst) {
    let rsp = await makePost(req, url)
    console.log('copyTask', req, rsp.data)
  }
}

async function getRunningTask(type, state) {
  'type: copy or aria2_transfer'
  state = state || 'undone'
  let url = `${host}/api/admin/task/${type}/${state}`
  return axios.get(url, getConfig())
}

async function cancelTasl(tasklist: any) {
  let url = `${host}/api/admin/task/aria2_down/cancel`
  let config = getConfig()
  config.params = {}
  for (let task of tasklist) {
    config.params.tid = task.id
    let rsp = await axios.post(url, {}, config)
    console.log('aria2_down/cancel', rsp.data)
  }

}

async function rmFilesInDir(dir: string, names: Array<string>) {
  if (!names) {
    let rsp = await loadFiles(dir)
    if (!rsp.data.data || (!rsp.data.data.content || rsp.data.data.content.length == 0)) {
      return
    }
    names = []
    for (let obj of rsp.data.data.content) {
      names.push(obj.name)
    }
  }
  let url = `${host}/api/fs/remove`
  let data = { dir: dir, names: names }
  return makePost(data, url)
}

async function clearTaskDone(type: string) {
  const url = `${host}/api/admin/task/${type}/clear_done`
  return makePost({}, url)
}

async function rmFailedFiles() {
  let rsp = await getRunningTask(taskType, 'done')
  console.log(taskType, 'done', rsp.data)
  let reg = /\[(?<a>.*?)\]\((?<b>\S+)\)/g
  if (rsp.data.data?.length > 0) {
    for (let task of rsp.data.data) {
      if (task.state !== 'errored') {
        continue
      }
      if (task.error.includes('incoming stream actual size')) {
        let lst = [...task.name.matchAll(reg)]
        let path = lst[0].groups.a + lst[0].groups.b
        let p = path.lastIndexOf('/')
        let rsp = await rmFilesInDir(path.substring(0, p), [path.substring(p + 1)])
        console.log('rm', path, rsp.data)
      }
    }
  }
  return clearTaskDone(taskType)
}

function writeData() {
  const opt = {
    flag: 'w', // a：追加写入；w：覆盖写入
  }
  fs.writeFile(jsonPath, JSON.stringify(lastDirFile, null, " "), opt, err => {
    if (err) {
      console.log(jsonPath, err)
    }
  })
}

function loadData() {
  let data = fs.readFileSync(jsonPath, {})
  lastDirFile = JSON.parse(data.toString())
  lastDirFile.find = 0
}

async function main() {
  if (process.argv.length > 2) {
    jsonPath = process.argv[2]
  }
  loadData()
  host = lastDirFile.host
  await getToken()
  let rsp = await getRunningTask(taskType, undefined)
  console.log('RunningTask', rsp.data)
  if (rsp.data.data?.length > 0) {
    // cancelTasl(rsp.data.data)
    console.log(`还在运行的任务数量：${rsp.data.data.length}`)
    return
  }
  rsp = await rmFailedFiles()
  console.log('clear task', rsp.data)
  // rmFilesInDir('/smb179/alist/temp/aria2')
  // let pathDst = '/123/game'
  // let pathSrc = '/移动159/game'

  let pathDst = lastDirFile.dst
  let pathSrc = lastDirFile.src
  // if (lastDirFile.todir) {
  //   pathDst = lastDirFile.todir
  //   pathSrc = lastDirFile.dir
  //   pathDst = pathDst.substring(0, pathDst.lastIndexOf('/'))
  //   pathSrc = pathSrc.substring(0, pathSrc.lastIndexOf('/'))
  // }

  let fileList = []
  await compare(pathDst, pathSrc, fileList)
  console.log('fileList length=', fileList.length)
  let rsp2 = copyTask(fileList)
  writeData()
  return rsp2
}

main().then()